// MMSP.sparse.hpp
// Class definition for the MMSP sparse data structure
// Questions/comments to gruberja@gmail.com (Jason Gruber)

#ifndef MMSP_SPARSE
#define MMSP_SPARSE
#include"MMSP.utility.hpp"

namespace MMSP{

template <typename T>
struct item{
	int index;
	T value;
};

template <typename T>
class sparse{
public:
	// constructors / destructor
	sparse() {size=0; data=reinterpret_cast<item<T>*>(malloc(sizeof(item<T>)));}
	~sparse() {free(data);}

	// data access operators
	T& set(int index)
	{
		for (int i=0; i<size; i++)
			if (data[i].index==index)
				return data[i].value;

		if (size==0) {
			size = 1;
			data[0].index = index;
			data[0].value = static_cast<T>(0);
			return data[0].value;
		}

		else {
			size += 1;
			data = reinterpret_cast<item<T>*>(realloc(data,size*sizeof(item<T>)));
			item<T>& last = data[size-1];
			last.index = index;
			last.value = static_cast<T>(0);
			return last.value;
		}
	}

	T operator[](int index) const
	{
		for (int i=0; i<size; i++)
			if (data[i].index==index)
				return data[i].value;
		return static_cast<T>(0);
	}

	int index(int i) const {return data[i].index;}

	T value(int i) const {return data[i].value;}

	// buffer I/O functions
	int buffer_size() const
		{return sizeof(size)+size*sizeof(item<T>);}
	int to_buffer(char* buffer) const {
		memcpy(buffer,&size,sizeof(size));
		memcpy(buffer+sizeof(size),data,size*sizeof(item<T>));
		return sizeof(size)+size*sizeof(item<T>);
	}
	int from_buffer(const char* buffer) {
		memcpy(&size,buffer,sizeof(size));
		data = reinterpret_cast<item<T>*>(realloc(data,size*sizeof(item<T>)));
		memcpy(data,buffer+sizeof(size),size*sizeof(item<T>));
		return sizeof(size)+size*sizeof(item<T>);
	}

	// file I/O functions
	void write(std::ofstream& file) const {
		file.write(reinterpret_cast<const char*>(&size),sizeof(size));
		file.write(reinterpret_cast<const char*>(data),size*sizeof(item<T>));
	}
	void read(std::ifstream& file) {
		file.read(reinterpret_cast<char*>(&size),sizeof(size));
		data = reinterpret_cast<item<T>*>(realloc(data,size*sizeof(item<T>)));
		file.read(reinterpret_cast<char*>(data),size*sizeof(item<T>));
	}

	// utility functions
	int length() const
		{return size;}
	void resize(int n) {

	}
	void copy(const sparse& s) {
		size = s.size;
		delete [] data;
		data = new item<T>[size];
		memcpy(data,s.data,size*sizeof(item<T>));
	}
	void swap(sparse& s) {
		item<T>* t = data;
		data = s.data;
		s.data = t;
		int* l = size;
		size = s.size;
		s.size = l;
	}
	

private:
	// object data
	item<T>* data;
	int size;
};

// buffer I/O functions
template <typename T> int buffer_size(const sparse<T>& s) {return s.buffer_size();}
template <typename T> int to_buffer(const sparse<T>& s, char* buffer) {return s.to_buffer(buffer);}
template <typename T> int from_buffer(sparse<T>& s, const char* buffer) {return s.from_buffer(buffer);}

// file I/O functions
template <typename T> void write(const sparse<T>& s, std::ofstream& file) {return s.write(file);}
template <typename T> void read(sparse<T>& s, std::ifstream& file) {return s.read(file);}

// utility functions
template <typename T> int length(const sparse<T>& s) {return s.length();}
template <typename T> void resize(sparse<T>& s, int n) {s.resize(n);}
template <typename T> void copy(sparse<T>& s, const sparse<T>& t) {s.copy(t);}
template <typename T> void swap(sparse<T>& s, sparse<T>& t) {s.swap(t);}

template <typename T> T& set(sparse<T>& s, int index) {return s.set(index);}
template <typename T> int index(const sparse<T>& s, int i) {return s.index(i);}
template <typename T> T value(const sparse<T>& s, int i) {return s.value(i);}
template <typename T> std::string name(const sparse<T>& s) {return std::string("sparse:")+name(T());}


// target class: dim = 0 specialization for sparse class
template <int ind, typename T>
class target<0,ind,sparse<T> >{
public:
	target(sparse<T>* DATA, const int* S0, const int* SX, const int* X0, const int* X1, const int* B0, const int* B1)
		{data=DATA; s0=S0; sx=SX; x0=X0; x1=X1; b0=B0; b1=B1;}

	operator sparse<T>&() {return *data;}
	operator const sparse<T>&() const {return *data;}

	const T operator[](int i) const {return data->operator[](i);}

	int buffer_size() const {return data->buffer_size();}
	int to_buffer(char* buffer) const {return data->to_buffer(buffer);}
	int from_buffer(const char* buffer) const {return data->from_buffer(buffer);}

	void write(std::ofstream& file) const {data->write(file);}
	void read(std::ifstream& file) const {data->read(file);}

	int length() const {return data->length();}
	int resize(int n) const {return data->resize(n);}
	void copy(const target& t) const {return data->copy(t->data);}
	void swap(const target& t) const {return data->swap(t->data);}

	T& set(int index) {return data->set(index);}
	int index(int i) const {return data->index(i);}
	T value(int i) const {return data->value(i);}

	sparse<T>* data;
	const int* s0;
	const int* sx;
	const int* x0;
	const int* x1;
	const int* b0;
	const int* b1;
};

template <int ind, typename T> T& set(const target<0,ind,sparse<T> >& s, int index) {return s.set(index);}
template <int ind, typename T> int index(const target<0,ind,sparse<T> >& s, int i) {return s.index(i);}
template <int ind, typename T> T value(const target<0,ind,sparse<T> >& s, int i) {return s.value(i);}

// buffer I/O functions
template <int ind, typename T> int buffer_size(const target<0,ind,sparse<T> >& s) {return s.buffer_size();}
template <int ind, typename T> int to_buffer(const target<0,ind,sparse<T> >& s, char* buffer) {return s.to_buffer(buffer);}
template <int ind, typename T> int from_buffer(const target<0,ind,sparse<T> >& s, const char* buffer) {return s.from_buffer(buffer);}

// file I/O functions
template <int ind, typename T> void write(const target<0,ind,sparse<T> >& s, std::ofstream& file) {return s.write(file);}
template <int ind, typename T> void read(const target<0,ind,sparse<T> >& s, std::ifstream& file) {return s.read(file);}

// utility functions
template <int ind, typename T> int length(const target<0,ind,sparse<T> >& s) {return s.length();}
template <int ind, typename T> void resize(const target<0,ind,sparse<T> >& s, int n) {s.resize(n);}
template <int ind, typename T> void copy(const target<0,ind,sparse<T> >& s, const target<0,ind,sparse<T> >& t) {s.copy(t);}
template <int ind, typename T> void swap(const target<0,ind,sparse<T> >& s, const target<0,ind,sparse<T> >& t) {s.swap(t);}
template <int ind, typename T> std::string name(const target<0,ind,sparse<T> >& s) {return std::string("sparse:")+name(T());}

} // namespace MMSP

#endif
